package com.epam.training.concurrency.first.task5;

import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.epam.training.concurrency.first.task3.CircularBuffer;

/**
 * 
 * @author Bogdan
 *
 */
public final class ThreadPool {
	private final int threadNumber;
	private final PoolWorker[] threads;
	private final LinkedList<Runnable> queue;

	/**
	 * 
	 * @param numberThreads
	 */
	public ThreadPool(int numberThreads) {
		this.threadNumber = numberThreads;
		queue = new LinkedList<Runnable>();
		threads = new PoolWorker[threadNumber];

		for (int i = 0; i < threadNumber; i++) {
			threads[i] = new PoolWorker();
		}
	}

	public void start() {
		for (int i = 0; i < threadNumber; i++) {
			threads[i].start();
		}
	}

	/**
	 * 
	 * @return threadNumber
	 */
	public int getThreadNumber() {
		return threadNumber;
	}

	/**
	 * 
	 * @param r
	 *            add new thread to queue
	 */
	public void execute(Runnable r) {
		synchronized (queue) {
			queue.addLast(r);
			queue.notify();
		}
	}

	/**
	 * 
	 * @author Bogdan
	 *
	 */
	private class PoolWorker extends Thread {
		public void run() {
			Runnable r;

			while (true) {
				synchronized (queue) {
					while (queue.isEmpty()) {
						try {
							queue.wait();
						} catch (InterruptedException ignored) {
							Logger.getLogger(CircularBuffer.class.getName())
									.log(Level.SEVERE, null, ignored);
						}
					}

					r = queue.removeFirst();
				}
				try {
					r.run();
				} catch (RuntimeException e) {
					Logger.getLogger(CircularBuffer.class.getName()).log(
							Level.WARNING, null, e);
				}
			}
		}
	}
}
